package es.cazadoresmadridejos.beans.manager.partner.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.displaytag.pagination.PaginatedList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.stereotype.Service;

import es.cazadoresmadridejos.beans.dao.partner.PartnerDao;
import es.cazadoresmadridejos.beans.manager.partner.PartnerManager;
import es.cazadoresmadridejos.common.bean.dao.Dao;
import es.cazadoresmadridejos.common.bean.manager.impl.ManagerImpl;
import es.cazadoresmadridejos.model.City;
import es.cazadoresmadridejos.model.Group;
import es.cazadoresmadridejos.model.Partner;
import es.cazadoresmadridejos.model.Partner.HunterType;
import es.cazadoresmadridejos.model.Partner.Role;
import es.cazadoresmadridejos.model.Partner.Sex;
import es.cazadoresmadridejos.model.Reason;
import es.cazadoresmadridejos.objs.tablrecords.BigGameOrderTableRecord;
import es.cazadoresmadridejos.objs.web.Page;

@Service
public class PartnerManagerImpl extends ManagerImpl<Partner> 
implements PartnerManager{

	@Autowired private PasswordEncoder passwordEncoder;
	
	@Override
	public Long save(Partner entity) {

		boolean deleteOld = false;
		boolean setNew = false;

		if(entity.getId() == null){//Si es nuevo y tiene compañero de monterias asignado se salvan ambos
			setNew = true;
			Long id = super.save(entity);
			if(entity.getPartner() != null && entity.getPartner().getId() != null){
				Partner p = get(entity.getPartner().getId());
				p.setPartner(entity);
				super.save(p);
			}
			return id;
		}

		Partner oldEntity = get(entity.getId());

		Long id = super.save(entity);


		if(oldEntity.getPartner() != null && entity.getPartner() == null){
			deleteOld = true;
		}else if(oldEntity.getPartner() != null && entity.getPartner() != null){
			if(!oldEntity.getPartner().getId().equals(entity.getPartner().getId())){
				deleteOld = true;
				setNew = true;
			}
		}else if(oldEntity.getPartner() == null && entity.getPartner() != null){
			setNew = true;
		}

		if(deleteOld){
			oldEntity.getPartner().setPartner(null);
			super.save(oldEntity.getPartner());
		}
		if(setNew){
			Partner newPartner = get(entity.getPartner().getId());
			newPartner.setPartner(entity);
			super.save(newPartner);
		}

		return id;
	}

	@Override
	public void delete(Long id) {
		Partner partner = get(id);

		if(partner.getPartner() != null){
			partner.getPartner().setPartner(null);
			save(partner.getPartner());
		}
		
		partner.setActive(0);
		partner.setNationalIdentityNumber(null);
		partner.setCity(null);
		partner.setEmail(null);
		partner.setMobile(null);
		partner.setPhone(null);
		save(partner);
	}

	@Autowired 
	public void setDao(@Qualifier("partnerDao")
	Dao<Partner> dao) {
		this.dao = dao;
	}

	@Override
	public Partner getByName(String userName) {
		return ((PartnerDao)dao).getByName(userName);
	}

	@Override
	public PaginatedList findAllPaginated(Page page) {
		return ((PartnerDao)dao).findAllPaginated(page);
	}

	@Override
	public String findAllForAutocomplete() {
		String result = "";
		List<Partner> list =  ((PartnerDao)dao).findAllForAutocomplete();

		result = transformForAutocomplete(result, list);
		return result;
	}

	@Override
	public String findAllForAutocompleteBigGame(Long id) {
		String result = "";
		List<Partner> list =  ((PartnerDao)dao).findAllForAutocompleteBigGame(id);

		result = transformForAutocomplete(result, list);
		return result;
	}

	private String transformForAutocomplete(String result, List<Partner> list) {
		for (Partner partner : list) {
			if(!StringUtils.isBlank(result)){
				result += ",";
			}
			result += "{label:'" + partner.getName() + " " +partner.getLastName() + "', value:'" + partner.getId() + "'}";

		}
		return result;
	}

	@Override
	public List<Partner> findAllByOrder(boolean hasBigGame, boolean hasDeer) {
		return ((PartnerDao)dao).findAllByOrder(hasBigGame,hasDeer);
	}

	//En partnerManager
	public List<Partner> findPartersFromOrderToBigGame(Integer numericValue, Integer stands,boolean hasBigGame, boolean hasDeer){
		List<Partner> list = ((PartnerDao)dao).findNext(numericValue, stands,hasBigGame, hasDeer);

		if(list.size() == stands){
			return list;
		}

		list.addAll( ((PartnerDao)dao).findNext(numericValue, stands - list.size(),hasBigGame,hasDeer) );

		return list;
	}

	@Override
	public void saveOrder(List<Long> ids, boolean isBigGame,boolean isDeer) {
		Integer count = 1;
		for (Long id : ids) {
			Partner partner = super.get(id);
			if(isBigGame){
				partner.setBigGameOrder(count);
			}
			if(isDeer){
				partner.setDeerOrder(count);
			}
			super.save(partner);
			count++;
		}
	}

	@Override
	public List<Partner> findPartersFromOrderToBigGame(Integer numeric,
			Integer stands, boolean hasBigGame, boolean hasDeer, Set<Long> partnersMap, List<Role> roles) {
		List<Partner> result = new ArrayList<Partner>(); 

		if(partnersMap.size() >= stands){
			return new ArrayList<Partner>();
		} 

		List<Partner> list = ((PartnerDao)dao).findPartersFromOrderToBigGame(numeric, hasBigGame, partnersMap,roles);
		Integer initSize = partnersMap.size();

		for (Partner partner : list) {
			if(partner.getPartner() == null){
				result.add(partner);
				partnersMap.add(partner.getId());
			}else{
				if(!partnersMap.contains(partner.getPartner().getId())){
					result.add(partner);
					partnersMap.add(partner.getId());
				}
			}
			//Si se completa la montería se sale del bucle
			if(result.size() + initSize == stands){
				break;
			}
		}

		return result;
	}

	@Override
	public Map<String,Integer> bigGameInfo(Integer numeric,
			Integer stands, List<Role> roles) {
		Map<String,Integer> result = new HashMap<String, Integer>();
		Set<Long> partnersMap = new HashSet<Long>();


		List<Partner> list = ((PartnerDao)dao).findPartersFromOrderToBigGame(numeric, true, partnersMap,roles);
		Integer initSize = partnersMap.size();
		int incjunta = 0;
		int incpartner = 0;

		for (Partner partner : list) {
			if(partner.getRole().equals(Role.JUNTA)){
				incjunta++;
			}

			if(partner.getPartner() == null){
				partnersMap.add(partner.getId());
			}else{
				if(!partnersMap.contains(partner.getPartner().getId())){
					partnersMap.add(partner.getId());
				}else{
					if(!partner.getRole().equals(Role.JUNTA)){
						incpartner++;
					}
				}
			}
			//Si se completa la montería se sale del bucle
			if(partnersMap.size() + initSize == stands){
				break;
			}
		}

		result.put("directives", incjunta);
		result.put("partners", incpartner);

		return result;
	}

	@Override
	public List<BigGameOrderTableRecord> findAllByOrder() {
		return ((PartnerDao)dao).findAllByOrder();
	}
	@Override
	public Integer getCountOfBigGameAssistances() {
		return ((PartnerDao)dao).getCountOfBigGameAssistances();
	}

	@Override
	public void importPartners() throws Throwable {
		Map<Integer, Partner> pairMap = new HashMap<Integer, Partner>();
		try{
			InputStream f = new FileInputStream(new File("D:/LISTADO.xlsx"));
			XSSFWorkbook wb     = new XSSFWorkbook(f);

			int rowNum = 1;

			XSSFSheet sheet = wb.getSheetAt(0);       // first sheet

			Set<String> userids = new HashSet<String>();

			
			while(sheet.getRow(rowNum)  != null){
				XSSFRow row     = sheet.getRow(rowNum);        // third row
				Partner partner = new Partner();
				partner.setActive(1);
				partner.setPartnerNumber(Double.valueOf(row.getCell(0).getNumericCellValue()).intValue());
				partner.setBirthDate(row.getCell(5).getDateCellValue());
				HunterType ht = HunterType.escopetero;
				String type = row.getCell(7).getStringCellValue();
				if("G".equals(type)){
					ht = HunterType.galguero;
				}
				if("E-J".equals(type)){
					ht = HunterType.escopetero_jubilado;
				}
				if("G-J".equals(type)){
					ht = HunterType.galguero_jubilado;
				}

				partner.setHunterType(ht);
				partner.setLastName(row.getCell(1).getStringCellValue());
				partner.setName(row.getCell(2).getStringCellValue());

				String addressData1 = row.getCell(6).getStringCellValue();

				String cp = addressData1.split(" ")[0];
				if(StringUtils.isNotBlank(cp)){
					partner.setPostalCode(Integer.valueOf(cp));
				}
				partner.setCity(new City());
				completeAddress(partner, addressData1);

				String addressData2 = row.getCell(3).getStringCellValue();
				partner.setStreet(addressData2);
				partner.setNationalIdentityNumber(row.getCell(4).getStringCellValue());

				//Si ya tenía un id antes no le asociamos uno nuevo
				String oldUserid = row.getCell(13) != null?row.getCell(13).getStringCellValue():null;

				if(oldUserid != null){
					if(userids.contains(oldUserid)){

						Partner p = getByName(oldUserid);
						if(p != null){
							int subindex = 1;
							while(userids.contains(extract(p.getName().substring(0,subindex)) + extract(p.getLastName().split(" ")[0] ))){
								subindex++;
							}
							p.setUserid(
									extract(p.getName().substring(0,subindex)) + extract(p.getLastName().split(" ")[0] )
									);
							p.setPassword(p.getUserid());
							save(p);
						}
					}

					partner.setUserid(oldUserid);
					partner.setPassword(oldUserid);
				}else{
					int subindex = 1;
					while(userids.contains(extract(partner.getName().substring(0,subindex)) + extract(partner.getLastName().split(" ")[0] ))){
						subindex++;
					}
					partner.setUserid(
							extract(partner.getName().substring(0,subindex)) + extract(partner.getLastName().split(" ")[0] )
							);
					userids.add(
							extract(partner.getName().substring(0,subindex)) + extract(partner.getLastName().split(" ")[0] )
							);

					partner.setPassword(partner.getUserid());
				}
				partner.setSelectedReason(new Reason(20122013l));
				if(partner.getName().toLowerCase().equals("amelia")){
					partner.setSex(Sex.MUJER);
				}else{
					partner.setSex(Sex.HOMBRE);
				}

				if(row.getCell(11) != null && "J".equals(row.getCell(11).getStringCellValue())){
					partner.setRole(Role.JUNTA);
				}else{
					partner.setRole(Role.CAZADOR);
				}
				
				if(row.getCell(14) != null && row.getCell(14).getNumericCellValue() == 1d){
					partner.setOnlyManteinance(true);
				}
				
				partner.setNewAdviceds(0);
				partner.setNewItems(0);
				partner.setNewPhotos(0);

				if(row.getCell(8) != null){
					partner.setGroup(new Group(Double.valueOf(row.getCell(8).getNumericCellValue()).longValue()));
				}
				if(row.getCell(9) != null){
					partner.setPhone(String.valueOf(row.getCell(9).getNumericCellValue()));
				}

				
				//Numero de pareja
				if(row.getCell(12) != null){
					partner.setHasBigGame(true);
					Double value = row.getCell(12).getNumericCellValue();
					if(value != 0d){
						if(pairMap.containsKey(value.intValue())){
							Partner partnerPair = pairMap.get(value.intValue());
							partnerPair.setPartner(partner);
							partner.setPartner(partnerPair);

							save(partner);
							save(partnerPair);
							pairMap.remove(partnerPair);
						}else{
							pairMap.put(value.intValue(), partner);
						}
					}
				}
				
				save(partner);
				
				rowNum++;
			}
			if(pairMap.size() > 0){
				for (Partner p : pairMap.values()) {
					System.out.println("El partner " + p.getName() + " " + p.getLastName() + " se ha quedado en el limbo.");
				}
			}
		}catch (Exception e) {
			e.printStackTrace();
			throw e;
		}
	}

	private String extract(String string){
		string = string.toLowerCase()
				.replaceAll("á", "a")
				.replaceAll("é", "e")
				.replaceAll("í", "i")
				.replaceAll("ó", "o")
				.replaceAll("ú", "u")
				.replaceAll("ñ", "n")
				.replaceAll("-", "")
				.replaceAll("_", "")
				.replaceAll("\\.", "")
				.replaceAll("º", "")
				.replaceAll("ª", "")
				.replaceAll("-", "")
				.replaceAll("è", "e")
				.replaceAll(" ", "")
				.replaceAll("è", "e");
		return string;
	}

	private void completeAddress(Partner partner, String addressData1) {
		if(addressData1.contains("Madridejos")){
			partner.getCity().setId(6858l);
		}
		if(addressData1.contains("Torrejón de Ardoz")){
			partner.getCity().setId(4429l);
		}
		if(addressData1.contains("Madrid")){
			partner.getCity().setId(4365l);
		}
		if(addressData1.contains("Mejorada del Campo")){
			partner.getCity().setId(4369l);
		}
		if(addressData1.contains("Consuegra")){
			partner.getCity().setId(6826l);
		}
		if(addressData1.contains("Arganda del Rey")){
			partner.getCity().setId(4300l);
		}
		if(addressData1.contains("San Fernando de Henares")){
			partner.getCity().setId(4413l);
		}
		if(addressData1.contains("Fuenlabrada")){
			partner.getCity().setId(4344l);
		}
		if(addressData1.contains("Toledo")){
			partner.getCity().setId(6940l);
		}
		if(addressData1.contains("Griñón")){
			partner.getCity().setId(4352l);
		}
		if(addressData1.contains("Camuñas")){
			partner.getCity().setId(6806l);
		}
		if(addressData1.contains("Villafranca de los Caballeros")){
			partner.getCity().setId(6958l);
		}
		if(addressData1.contains("Alcalá de Henares")){
			partner.getCity().setId(4291l);
		}
		if(addressData1.contains("Aranjuez")){
			partner.getCity().setId(4299l);
		}
		if(addressData1.contains("Villacañas")){
			partner.getCity().setId(6957l);
		}
	}

	@Override
	public List<BigGameOrderTableRecord> findAllByAutoOrder() {
		Map<Long, Integer> orders = new HashMap<Long, Integer>();
		Integer countOrders = 0;
		Set<Long> idPartners = new HashSet<Long>();
		
		List<BigGameOrderTableRecord> list = findAllByOrder();
		
		List<BigGameOrderTableRecord> l1 = new ArrayList<BigGameOrderTableRecord>();
		List<BigGameOrderTableRecord> singles = new ArrayList<BigGameOrderTableRecord>();
		List<BigGameOrderTableRecord> s1 = new ArrayList<BigGameOrderTableRecord>();
		List<BigGameOrderTableRecord> s2 = new ArrayList<BigGameOrderTableRecord>();
		List<BigGameOrderTableRecord> l2 = new ArrayList<BigGameOrderTableRecord>();
		
		List<BigGameOrderTableRecord> result = new ArrayList<BigGameOrderTableRecord>();
		
		for (BigGameOrderTableRecord bigGameOrderTableRecord : list) {

			if(bigGameOrderTableRecord.getPartnerPartnerId() != null){
				if(idPartners.contains(bigGameOrderTableRecord.getPartnerPartnerId())){
					l2.add(bigGameOrderTableRecord);
				}else{
					orders.put(bigGameOrderTableRecord.getPartnerId(),countOrders++);
					
					l1.add(bigGameOrderTableRecord);
					idPartners.add(bigGameOrderTableRecord.getPartnerId());
				}
			}else{
				singles.add(bigGameOrderTableRecord);
			}
		}
		
		int size = singles.size();
		
		int point = size / 2;
		
		Collections.sort(l2, new PartnerComparator(orders));
		
		s1.addAll(singles.subList(0, point));
		s2.addAll(singles.subList(point, size));
		result.addAll(l1);
		result.addAll(s1);
		
		result.addAll(l2);
		result.addAll(s2);
		
		return result;
	}
	
	private class PartnerComparator implements Comparator<BigGameOrderTableRecord>{
		private Map<Long, Integer> orders = new HashMap<Long, Integer>();
		public PartnerComparator(Map<Long, Integer> orders){
			this.orders = orders;
		}

		@Override
		public int compare(BigGameOrderTableRecord o1,
				BigGameOrderTableRecord o2) {
			Long p1 = o1.getPartnerPartnerId();
			Long p2 = o2.getPartnerPartnerId();
			
			Integer i1 = orders.get(p1);
			Integer i2 = orders.get(p2);
			
			return i1.compareTo(i2);
		}
	}
	
	public static  void main(String[] args) {
		List<Integer> longs = new ArrayList<Integer>();
		List<Integer> s1 = new ArrayList<Integer>();
		List<Integer> s2 = new ArrayList<Integer>();
		longs.add(1);
		longs.add(2);
		longs.add(3);
		longs.add(4);
		longs.add(5);
		longs.add(6);
		longs.add(7);
		
		int size = longs.size();
		
		int point = size / 2;
		
		s1.addAll(longs.subList(0, point));
		s2.addAll(longs.subList(point, size));
		for (Integer integer : s1) {
				System.out.println(integer);
		}
		for (Integer integer : s2) {
			System.out.println(integer);
		}
		
	}
}

